package com.battle.service.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.battle.pojo.entity.*;
import com.battle.pojo.enums.StudyStatusEnum;
import com.battle.pojo.enums.WarCaseStudyDetailsStatusEnum;
import com.battle.pojo.enums.WarCaseStudyUserTypeEnum;
import com.battle.pojo.param.caseBaseInfo.CaseStatisticsParam;
import com.battle.pojo.param.caseBaseInfo.GetCaseDiscountingParam;
import com.battle.pojo.param.warCaseStudy.*;
import com.battle.pojo.vo.caseBaseInfo.*;
import com.battle.pojo.vo.warCaseStudy.*;
import com.battle.pojo.dto.warCaseStudy.*;
import com.battle.service.repository.in.*;
import com.battle.service.service.in.WarCaseStudyService;
import nirvana.core.domains.vo.PageResult;
import nirvana.core.utils.ids.IdGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 【描 述】：战例研讨服务
 * 【环 境】：J2SE 17
 * 【详 细】：
 */
@Service
public class WarCaseStudyServiceImpl implements WarCaseStudyService {

    private final WarCaseStudyRepository warCaseStudyRepository;
    private final WarCaseStudyUserRepository studyUserRepository;
    private final UserRepository userRepository;
    private final StringRedisTemplate stringRedisTemplate;
    private final CaseBaseInfoRepository caseBaseInfoRepository;
    private final ApplicationFeedbackRepository applicationFeedbackRepository;
    /**
     * 战例研讨数量
     */
    private final String CASE_LEARN_COUNT_KEY = "CASE_LEARN_COUNT_KEY_";

    public WarCaseStudyServiceImpl(WarCaseStudyRepository warCaseStudyRepository, WarCaseStudyUserRepository studyUserRepository, UserRepository userRepository, StringRedisTemplate stringRedisTemplate, CaseBaseInfoRepository caseBaseInfoRepository, ApplicationFeedbackRepository applicationFeedbackRepository) {
        this.warCaseStudyRepository = warCaseStudyRepository;
        this.studyUserRepository = studyUserRepository;
        this.userRepository = userRepository;
        this.stringRedisTemplate = stringRedisTemplate;
        this.caseBaseInfoRepository = caseBaseInfoRepository;
        this.applicationFeedbackRepository = applicationFeedbackRepository;
    }


    /**
     * 创建战例研讨
     *
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createWarCaseStudy(CreateWarCaseStudyParam param) {
        WarCaseStudy warCaseStudy = new WarCaseStudy();
        BeanUtils.copyProperties(param, warCaseStudy);
        Long id = IdGenerator.SNOW.generate();
        warCaseStudy.setId(id);
        warCaseStudy.setStatus(StudyStatusEnum.underway);
        warCaseStudyRepository.create(warCaseStudy);

        //加入战例研讨数量
        if (param.getCaseId()!=null){
            String idStr = param.getCaseId().toString();
            stringRedisTemplate.opsForZSet().incrementScore(CASE_LEARN_COUNT_KEY, idStr, 1);
        }

        //邀请用户
        if (param.getUserIds() != null && CollectionUtil.isNotEmpty(param.getUserIds())) {
            createStudyUser(warCaseStudy.getCaseId(), warCaseStudy.getId(), warCaseStudy.getInitiatorId(), param.getUserIds(), WarCaseStudyUserTypeEnum.invited);
        }
    }

    /**
     * 报名战例研讨
     *
     * @param studyId
     * @param userId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void applyCaseStudy(Long studyId, Long userId) {
        WarCaseStudy warCaseStudy = warCaseStudyRepository.getByIdCheck(studyId);
        List<Long> userIds = new ArrayList<>();
        userIds.add(userId);
        createStudyUser(warCaseStudy.getCaseId(), warCaseStudy.getId(), warCaseStudy.getInitiatorId(), userIds, WarCaseStudyUserTypeEnum.apply);
    }

    /**
     * 邀请用户战例研讨
     *
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void inviteCaseStudy(InviteCaseStudyParam param) {
        WarCaseStudy warCaseStudy = warCaseStudyRepository.getByIdCheck(param.getStudyId());
        if (param.getUserIds() != null && CollectionUtil.isNotEmpty(param.getUserIds())) {
            createStudyUser(warCaseStudy.getCaseId(), warCaseStudy.getId(), warCaseStudy.getInitiatorId(), param.getUserIds(), WarCaseStudyUserTypeEnum.invited);
        }
    }

    /**
     * 邀请用户或者用户报名
     *
     * @param caseId
     * @param studyId
     * @param initiatorId
     * @param userId
     * @param type
     */
    void createStudyUser(Long caseId, Long studyId, Long initiatorId, List<Long> userId, WarCaseStudyUserTypeEnum type) {
        List<WarCaseStudyUser> userList = new ArrayList<>();

        if (CollectionUtil.isNotEmpty(userId)) {
            for (Long id : userId) {
                WarCaseStudyUser user = new WarCaseStudyUser();
                user.setStudyId(studyId);
                user.setCaseId(caseId);
                user.setInitiatorId(initiatorId);
                user.setId(IdGenerator.SNOW.generate());
                user.setUserId(id);
                user.setType(type);
                user.setStatus(WarCaseStudyDetailsStatusEnum.wait);
                userList.add(user);
            }
        }
        studyUserRepository.saveBatch(userList);
    }


    /**
     * 修改战例研讨
     *
     * @param param
     */
    @Override
    public void editWarCaseStudy(EditWarCaseStudyParam param) {
        Long id = param.getId();
        WarCaseStudy warCaseStudy = warCaseStudyRepository.getByIdCheck(id);
        BeanUtils.copyProperties(param, warCaseStudy);
        warCaseStudy.setStatus(StudyStatusEnum.finish);
        warCaseStudyRepository.edit(warCaseStudy);
    }

    /**
     * 查看研讨成果
     *
     * @param id
     * @return
     */
    @Override
    public EditWarCaseStudyParam getEditWarCaseStudyParam(Long id) {
        EditWarCaseStudyParam param = new EditWarCaseStudyParam();
        WarCaseStudy warCaseStudy = warCaseStudyRepository.getByIdCheck(id);
        BeanUtils.copyProperties(warCaseStudy, param);
        return param;
    }

    /**
     * 修改研讨成果
     *
     * @param param
     */
    @Override
    public void editWarCaseResult(EditWarCaseStudyParam param) {
        WarCaseStudy warCaseStudy = warCaseStudyRepository.getByIdCheck(param.getId());
        BeanUtils.copyProperties(param, warCaseStudy);
        warCaseStudyRepository.updateById(warCaseStudy);
    }

    /**
     * 删除研讨成果
     *
     * @param id
     */
    @Override
    public void removeWarCaseResult(Long id) {
        WarCaseStudy warCaseStudy = warCaseStudyRepository.getByIdCheck(id);
        warCaseStudy.setStatus(StudyStatusEnum.underway);
        warCaseStudy.setResult("");
        warCaseStudy.setResultPicture(new ArrayList<>());
        warCaseStudyRepository.updateById(warCaseStudy);
    }

    /**
     * 移除战例研讨
     *
     * @param id
     */
    @Override
    public void removeWarCaseStudy(Long id) {
        WarCaseStudy study = warCaseStudyRepository.getByIdCheck(id);
        warCaseStudyRepository.removeById(id);

        if (study.getCaseId()!=null){
            //减少战例研讨数量
            String idStr = study.getCaseId().toString();
            stringRedisTemplate.opsForZSet().incrementScore(CASE_LEARN_COUNT_KEY, idStr, -1);
        }
    }

    /**
     * 启动/禁用战例研讨
     *
     * @param id
     */
    @Override
    public void enabledWarCaseStudy(Long id) {
        WarCaseStudy warCaseStudy = warCaseStudyRepository.getByIdCheck(id);
        warCaseStudy.setIsDisable(!warCaseStudy.getIsDisable());
        warCaseStudyRepository.edit(warCaseStudy);
    }

    /**
     * 获取战例研讨详情
     *
     * @param id
     * @return
     */
    @Override
    public GetWarCaseStudyVo getWarCaseStudy(Long id) {
        WarCaseStudy warCaseStudy = warCaseStudyRepository.getByIdCheck(id);
        GetWarCaseStudyVo vo = new GetWarCaseStudyVo();
        BeanUtils.copyProperties(warCaseStudy, vo);
        return vo;
    }

    /**
     * 获取战例研讨 列表
     *
     * @param param
     * @return
     */
    @Override
    public PageResult<GetWarCaseStudyListVo> getWarCaseStudyList(GetWarCaseStudyListParam param) {

        SelectWarCaseStudyDto dto = new SelectWarCaseStudyDto();
        BeanUtils.copyProperties(param, dto);
        Page<WarCaseStudy> page = warCaseStudyRepository.selectWarCaseStudy(dto);
        List<WarCaseStudy> warCaseStudyList = page.getRecords();
        List<GetWarCaseStudyListVo> list = new ArrayList<>();

        if (CollectionUtil.isNotEmpty(warCaseStudyList)) {
            List<Long> userIds = new ArrayList<>();
            warCaseStudyList.forEach(v -> {
                userIds.add(v.getInitiatorId());
            });

            List<Long> studyIds = warCaseStudyList.stream().map(WarCaseStudy::getId).toList();

            Map<Long, List<WarCaseStudyUserDto>> listMap = studyUserRepository.getListByStudyIds(studyIds);
            Map<Long, User> userMap = userRepository.getMap(userIds);

            for (WarCaseStudy warCaseStudy : warCaseStudyList) {
                GetWarCaseStudyListVo vo = new GetWarCaseStudyListVo();
                BeanUtils.copyProperties(warCaseStudy, vo);
                User operation = userMap.get(warCaseStudy.getInitiatorId());
                if (operation != null) {
                    vo.setInitiatorName(operation.getName());
                }

                List<WarCaseStudyUserDto> dtoList = listMap.get(warCaseStudy.getId());
                if (dtoList != null) {
                    String names = dtoList.stream()
                            .map(WarCaseStudyUserDto::getUserName)
                            .collect(Collectors.joining(","));
                    vo.setParticipant(names);
                }
                list.add(vo);
            }
        }
        return new PageResult<>(list, page);

    }

    /**
     * 获取战例研讨下拉列表
     *
     * @param param
     * @return
     */
    @Override
    public List<GetWarCaseStudyDownListVo> getWarCaseStudyDownList(GetWarCaseStudyDownListParam param) {
        WarCaseStudy po = new WarCaseStudy();
        if (param != null) {
            BeanUtils.copyProperties(param, po);
        }
        List<WarCaseStudy> warCaseStudyList = warCaseStudyRepository.getListByEntity(po);

        List<GetWarCaseStudyDownListVo> list = new ArrayList<>();
        for (WarCaseStudy warCaseStudy : warCaseStudyList) {
            GetWarCaseStudyDownListVo vo = new GetWarCaseStudyDownListVo();
            BeanUtils.copyProperties(warCaseStudy, vo);
            list.add(vo);
        }
        return list;
    }


    /**
     * 战例研讨排行榜
     *
     * @param
     * @return
     */
    @Override
    public List<CaseRankingListVo> getCaseRankingList() {
        List<CaseRankingListVo> voList = new ArrayList<>();
        Set<ZSetOperations.TypedTuple<String>> set = stringRedisTemplate.opsForZSet().reverseRangeByScoreWithScores(CASE_LEARN_COUNT_KEY, 0, 4);

        for (ZSetOperations.TypedTuple<String> tuple : set) {
            CaseRankingListVo vo = new CaseRankingListVo();
            String key = tuple.getValue();
            double score = tuple.getScore();
            Integer val = (int) score;
            vo.setCaseId(Long.parseLong(key));
            vo.setCount(val);

            CaseBaseInfo byId = caseBaseInfoRepository.getById(vo.getCaseId());
            if (byId != null) {
                vo.setCaseName(byId.getName());
            }
            voList.add(vo);
        }
        return voList;
    }

    /**
     * 战例统计数量
     *
     * @return
     */
    @Override
    public CaseStatisticsVo getCaseStatistics() {
        CaseStatisticsVo vo = new CaseStatisticsVo();

        Integer caseCount = caseBaseInfoRepository.getBaseMapper().selectCount(
                new LambdaQueryWrapper<CaseBaseInfo>()
                        .eq(CaseBaseInfo::getIsDelete, false)
        ).intValue();
        vo.setCaseCount(caseCount);

        Integer warCaseStudyCount = warCaseStudyRepository.getBaseMapper().selectCount(
                new LambdaQueryWrapper<WarCaseStudy>()
                        .eq(WarCaseStudy::getIsDelete, false)
        ).intValue();
        vo.setWarCaseStudyCount(warCaseStudyCount);

        Integer warCaseStudyOverCount = warCaseStudyRepository.getBaseMapper().selectCount(
                new LambdaQueryWrapper<WarCaseStudy>()
                        .eq(WarCaseStudy::getIsDelete, false)
                        .eq(WarCaseStudy::getStatus, StudyStatusEnum.finish)
        ).intValue();
        vo.setWarCaseStudyOverCount(warCaseStudyOverCount);

        Integer applicationFeedbackCount = applicationFeedbackRepository.getBaseMapper().selectCount(
                new LambdaQueryWrapper<ApplicationFeedback>()
                        .eq(ApplicationFeedback::getIsDelete, false)
        ).intValue();
        vo.setApplicationFeedbackCount(applicationFeedbackCount);

        return vo;
    }

    @Override
    public CaseCakeVo getCaseCake(CaseStatisticsParam param) {
        CaseCakeVo vo = new CaseCakeVo();
        List<CaseCakeDetailsVo> voList = new ArrayList<>();

        switch (param.getType()) {
            case 0:
                //战例类别
                voList = warCaseStudyRepository.getCaseCakeVoList(param.getStartTime(), param.getEndTime());
                break;
            case 1:
                //研讨成果
                voList= warCaseStudyRepository.getStudyCakeVoList(param.getStartTime(), param.getEndTime(),StudyStatusEnum.finish,null);
                break;
            case 2:
                //专家参与类型
                voList= warCaseStudyRepository.getStudyCakeVoList(param.getStartTime(), param.getEndTime(),null,true);
                break;
            case 3:
                //研讨关键词
                voList= warCaseStudyRepository.getStudyCakeVoList(param.getStartTime(), param.getEndTime(),null,null);
                break;
            case 4:
                //研讨内容类型
                voList = warCaseStudyRepository.getStudyCakeVoList(param.getStartTime(), param.getEndTime(),null,null);
                break;
            default:
                break;
        }

        vo.setCakeDetailsVos(voList);
        return vo;
    }

    @Override
    public CaseDiscountingVo getCaseDiscounting(GetCaseDiscountingParam param) {
        CaseDiscountingVo vo = new CaseDiscountingVo();
        //时间区间有多少个月份
        List<String> xData = getBetweenMonth(param.getStartTime(), param.getEndTime());
        if (CollectionUtil.isEmpty(xData)) return vo;

        List<CaseDiscountingDetailsVo> itemList = new ArrayList<>();

        //战例
        CaseDiscountingDetailsVo caseVo = new CaseDiscountingDetailsVo();
        List<BigDecimal> caseValueList = new ArrayList<>();
        caseVo.setName("战例数增长");
        List<CaseCakeDetailsVo> caseTimeVoList = warCaseStudyRepository.getCaseTimeVoList(param.getStartTime(), param.getEndTime());
        Map<String, CaseCakeDetailsVo> caseTimeVoListMp = new HashMap<>();
        if (CollectionUtil.isNotEmpty(caseTimeVoList)) {
            caseTimeVoListMp = caseTimeVoList.stream().collect(Collectors.toMap(CaseCakeDetailsVo::getName, v -> v));
        }

        for (String xDatum : xData) {
            CaseCakeDetailsVo caseCakeDetailsVo = caseTimeVoListMp.get(xDatum);
            if (caseCakeDetailsVo != null) {
                caseValueList.add(caseCakeDetailsVo.getNumber());
            } else {
                caseValueList.add(BigDecimal.ZERO);
            }
        }
        caseVo.setValueList(caseValueList);

        //研讨
        CaseDiscountingDetailsVo studyVo = new CaseDiscountingDetailsVo();
        List<BigDecimal> studyValueList = new ArrayList<>();
        List<CaseCakeDetailsVo> studyTimeVoList = warCaseStudyRepository.getStudyTimeVoList(param.getStartTime(), param.getEndTime());
        Map<String, CaseCakeDetailsVo> studyTimeVoListMp = new HashMap<>();
        if (CollectionUtil.isNotEmpty(studyTimeVoList)) {
            studyTimeVoListMp = studyTimeVoList.stream().collect(Collectors.toMap(CaseCakeDetailsVo::getName, v -> v));
        }
        studyVo.setName("研讨数增长");
        for (String xDatum : xData) {
            CaseCakeDetailsVo caseCakeDetailsVo = studyTimeVoListMp.get(xDatum);
            if (caseCakeDetailsVo != null) {
                studyValueList.add(caseCakeDetailsVo.getNumber());
            } else {
                studyValueList.add(BigDecimal.ZERO);
            }
        }
        studyVo.setValueList(studyValueList);

        itemList.add(caseVo);
        itemList.add(studyVo);
        vo.setItemList(itemList);
        vo.setXData(xData);
        return vo;
    }

    //获得两个日期之间所有的月
    public List<String> getBetweenMonth(LocalDate start, LocalDate end) {
        List<String> result = new ArrayList<>();

        int startYear = start.getYear();
        int startMonth = start.getMonthValue();
        int endYear = end.getYear();
        int endMonth = end.getMonthValue();

        while (startYear < endYear || (startYear == endYear && startMonth <= endMonth)) {
            result.add(startYear + "-" + (startMonth < 10 ? "0" + startMonth : startMonth));

            if (startMonth == 12) {
                startYear++;
                startMonth = 1;
            } else {
                startMonth++;
            }
        }
        return result;
    }

}



